<!DOCTYPE HTML PUBLIC "-//ORA//DTD CD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE>[Chapter 10] 10.3 A More Complex Bean</TITLE>
<META NAME="author" CONTENT="David Flanagan">
<META NAME="date" CONTENT="Thu Jul 31 15:57:46 1997">
<META NAME="form" CONTENT="html">
<META NAME="metadata" CONTENT="dublincore.0.1">
<META NAME="objecttype" CONTENT="book part">
<META NAME="otheragent" CONTENT="gmat dbtohtml">
<META NAME="publisher" CONTENT="O'Reilly &amp; Associates, Inc.">
<META NAME="source" CONTENT="SGML">
<META NAME="subject" CONTENT="Java">
<META NAME="title" CONTENT="Java in a Nutshell">
<META HTTP-EQUIV="Content-Script-Type" CONTENT="text/javascript">
</HEAD>
<body vlink="#551a8b" alink="#ff0000" text="#000000" bgcolor="#FFFFFF" link="#0000ee">

<DIV CLASS=htmlnav>
<H1><a href='index.htm'><IMG SRC="gifs/smbanner.gif"
     ALT="Java in a Nutshell" border=0></a></H1>
<table width=515 border=0 cellpadding=0 cellspacing=0>
<tr>
<td width=172 align=left valign=top><A HREF="ch10_02.htm"><IMG SRC="gifs/txtpreva.gif" ALT="Previous" border=0></A></td>
<td width=171 align=center valign=top><B><FONT FACE="ARIEL,HELVETICA,HELV,SANSERIF" SIZE="-1">Chapter 10<br>Java Beans</FONT></B></TD>
<td width=172 align=right valign=top><A HREF="ch10_04.htm"><IMG SRC="gifs/txtnexta.gif" ALT="Next" border=0></A></td>
</tr>
</table>

&nbsp;
<hr align=left width=515>
</DIV>
<DIV CLASS=sect1>
<h2 CLASS=sect1><A CLASS="TITLE" NAME="JNUT2-CH-10-SECT-3">10.3 A More Complex Bean</A></h2>

<P CLASS=para>
<A HREF="ch10_03.htm#JNUT2-CH-10-EX-2">Example 10.2</A>
shows another bean, <tt CLASS=literal>YesNoDialog</tt>.  This bean creates
a dialog box that displays a simple message to the user and
asks the user to respond by clicking the <b>Yes</b>,
<b>No</b>, or <b>Cancel</b> button.
<A HREF="ch10_03.htm#JNUT2-CH-10-FIG-1">Figure 10.1</A>
shows the bean being manipulated in Sun's <I CLASS=emphasis>beanbox</I> tool
and also shows a dialog displayed by the bean.

<DIV CLASS=figure>
<h4 CLASS=figure><A CLASS="TITLE" NAME="JNUT2-CH-10-FIG-1">Figure 10.1: The YesNoDialog bean in the <I CLASS=emphasis>beanbox</I></A></h4>


<p>
<img align=middle src="./figs/jn2_1001.gif" alt="[Graphic: Figure 10-1]" width=464 height=321 border=0>

</DIV>

<P CLASS=para>
The <tt CLASS=literal>YesNoDialog</tt> bean uses a custom
<tt CLASS=literal>AnswerEvent</tt> type to notify <tt CLASS=literal>AnswerListener</tt>
objects when the user has dismissed the dialog by clicking
on one of its three buttons.  This new event class and
listener interface are defined in the next section.

<P CLASS=para>
Note that <tt CLASS=literal>YesNoDialog</tt> is a subclass of
<tt CLASS=literal>Object</tt>, not <tt CLASS=literal>Dialog</tt>.  This is a result of the
requirement for a bean to have a no-argument constructor.
Because all dialog boxes must be associated with a
<tt CLASS=literal>Frame</tt>, <tt CLASS=literal>Dialog</tt> does not have a no-argument
constructor, and this means that subclasses of
<tt CLASS=literal>Dialog</tt> cannot have meaningful no-argument
constructors, either.  As a result, <tt CLASS=literal>YesNoDialog</tt>
defers creation of its window and associated GUI
components until it is actually popped up with the
<tt CLASS=literal>display()</tt> method.  Another <I CLASS=emphasis>beanbox</I>
shortcoming is that it only recognizes methods with no arguments.
[1]
For this reason, the <tt CLASS=literal>display()</tt> method has no
arguments, and so no <tt CLASS=literal>Frame</tt> can be specified through
that method either.  Since a parent <tt CLASS=literal>Frame</tt> cannot be
specified, <tt CLASS=literal>YesNoDialog</tt> cannot create a
<tt CLASS=literal>Dialog</tt> object, and instead simulates a dialog box
with a <tt CLASS=literal>Frame</tt> window.  An alternative would have been
to define a bean property through which the required
<tt CLASS=literal>Frame</tt> could be specified.

<blockquote class=footnote>
<P CLASS=para>[1] 
The <I CLASS=emphasis>beanbox</I> tool shipped with the February 1997
version of the BDK has a number of shortcomings.  In part, this is
due to the fact that the BDK is a new technology and not as
stable or robust as the JDK.  It is also because
<I CLASS=emphasis>beanbox</I> is intended as a test environment, not an
actual programmer's tool.
</blockquote>
<P CLASS=para>
Since <tt CLASS=literal>YesNoDialog</tt> is not a subclass of
<tt CLASS=literal>Component</tt>, it has to define its own properties and
accessor methods for fonts and colors; normally these would
simply be inherited from <tt CLASS=literal>Component</tt>.  Since this bean
is not a <tt CLASS=literal>Component</tt> subclass, it is an "invisible"
bean that does not have a graphical representation of its
own.  (It pops up a window when the <tt CLASS=literal>display()</tt> method
is called, but that is not the same as having a graphical
representation that appears within another window.)
Different tools treat invisible beans differently.
<I CLASS=emphasis>beanbox</I> simply displays the classname of invisible
beans.

<P CLASS=para>
Notice that <tt CLASS=literal>YesNoDialog</tt> does not use any classes
from the <tt CLASS=literal>java.beans</tt> package.  One of the surprising
things about beans is that they typically do not have to use
any classes from this package.  As we'll see in later
sections, it is the auxiliary classes that are shipped with
a bean that make heavy use of that package.

<DIV CLASS=example>
<h4 CLASS=example><A CLASS="TITLE" NAME="JNUT2-CH-10-EX-2">Example 10.2: The YesNoDialog Bean</A></h4>

<DIV CLASS=screen>
<P>
<PRE>
package oreilly.beans.yesno;      // Put this bean in its own private package.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class YesNoDialog {
  // Properties of the bean.
  protected String message, title;
  protected String yesLabel, noLabel, cancelLabel;
  protected int alignment;
  protected Font font = new Font("Serif", Font.PLAIN, 12);
  protected Color background = SystemColor.control;
  protected Color foreground = SystemColor.controlText;
  // Constants for the alignment property.
  public static final int LEFT = MultiLineLabel.LEFT;
  public static final int RIGHT = MultiLineLabel.RIGHT;
  public static final int CENTER = MultiLineLabel.CENTER;
  // Methods to query all of the bean properties.
  public String getMessage() { return message; }
  public String getTitle() { return title; }
  public String getYesLabel() { return yesLabel; }
  public String getNoLabel() { return noLabel; }
  public String getCancelLabel() { return cancelLabel; }
  public int getAlignment() { return alignment; }
  public Font getFont() { return font; }
  public Color getBackground() { return background; }
  public Color getForeground() { return foreground; }
  // Methods to set all of the bean properties.
  public void setMessage(String m) { message = m; }
  public void setTitle(String t) { title=t; }
  public void setYesLabel(String l) { yesLabel = l; }
  public void setNoLabel(String l) { noLabel = l; }
  public void setCancelLabel(String l) { cancelLabel = l; }
  public void setAlignment(int a) { alignment = a; }
  public void setFont(Font f) { font = f; }
  public void setBackground(Color bg) { background = bg; }
  public void setForeground(Color fg) { foreground = fg; }
  /** This field holds a list of registered ActionListeners.
   *  Vector is internally synchronized to prevent race conditions. */
  protected Vector listeners = new Vector();
  /** Register an action listener to be notified when a button is pressed. */
  public void addAnswerListener(AnswerListener l) {
    listeners.addElement(l);
  }
  /** Remove an Answer listener from our list of interested listeners. */
  public void removeAnswerListener(AnswerListener l) {
    listeners.removeElement(l);
  }
  /** Send an event to all registered listeners. */
  public void fireEvent(AnswerEvent e) {
    // Make a copy of the list and fire the events using that copy.
    // This means that listeners can be added or removed from the original
    // list in response to this event.  We ought to be able to just use an
    // enumeration for the vector, but that doesn't copy the list internally.
    Vector list = (Vector) listeners.clone();
    for(int i = 0; i &lt; list.size(); i++) {
      AnswerListener listener = (AnswerListener)list.elementAt(i);
      switch(e.getID()) {
      case AnswerEvent.YES: listener.yes(e); break;
      case AnswerEvent.NO:  listener.no(e); break;
      case AnswerEvent.CANCEL: listener.cancel(e); break;
      }
    }
  }
  /** The no-argument bean constructor, with default property values */
  public YesNoDialog() {
    this("Question", "Your\nMessage\nHere", "Yes", "No", "Cancel", LEFT);
  }
  /** A constructor for programmers using this class "by hand". */
  public YesNoDialog(String title, String message,
                     String yesLabel, String noLabel, String cancelLabel,
                     int alignment) {
    this.title = title;
    this.message = message;
    this.yesLabel = yesLabel;
    this.noLabel = noLabel;
    this.cancelLabel = cancelLabel;
    this.alignment = alignment;
  }
  /** This method makes the bean display the dialog box. */
  public void display() {
    // Create a frame with the specified title.  It would be nice to
    // use a Dialog, but that needs to be passed a Frame argument, and
    // the BDK beanbox tool only seems to work with no-argument methods.
    final Frame frame = new Frame(title);
    // Specify a LayoutManager for it.
    frame.setLayout(new BorderLayout(15, 15));
    // Specify font and colors, if any are specified.
    if (font != null) frame.setFont(font);
    if (background != null) frame.setBackground(background);
    if (foreground != null) frame.setForeground(foreground);
    // Put the message label in the middle of the window.
    frame.add("Center", new MultiLineLabel(message, 20, 20, alignment));
    // Create an action listener for use by the buttons of the dialog.
    // When a button is pressed, this listener first closes the dialog box.
    // Then, it creates an AnswerEvent object that corresponds to the
    // button that was pressed, and sends that new event to all registered
    // listeners, using the fireEvent() method defined above.
    ActionListener listener = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        frame.dispose();     // Pop down window.
        if (listeners != null) {      // Notify any registered listeners.
          String cmd = e.getActionCommand();
          int type;
          if (cmd.equals("yes")) type = AnswerEvent.YES;
          else if (cmd.equals("no")) type = AnswerEvent.NO;
          else type = AnswerEvent.CANCEL;
          fireEvent(new AnswerEvent(YesNoDialog.this, type));
        }
      }
    };
    // Create a panel for the dialog buttons and put it at the bottom
    // of the dialog.  Specify a FlowLayout layout manager for it.
    Panel buttonbox = new Panel();
    buttonbox.setLayout(new FlowLayout(FlowLayout.CENTER, 25, 15));
    frame.add("South", buttonbox);
    // Create each specified button, specifying the action listener
    // and action command for each, and adding them to the buttonbox.
    if ((yesLabel != null) &amp;&amp; (yesLabel.length() &gt; 0)) {
      Button yes = new Button(yesLabel);        // Create button.
      yes.setActionCommand("yes");              // Set action command.
      yes.addActionListener(listener);          // Set listener.
      buttonbox.add(yes);                       // Add button to the panel.
    }
    if ((noLabel != null) &amp;&amp; (noLabel.length() &gt; 0)) {
      Button no = new Button(noLabel);
      no.setActionCommand("no");
      no.addActionListener(listener);
      buttonbox.add(no);
    }
    if ((cancelLabel != null) &amp;&amp; (cancelLabel.length() &gt; 0)) {
      Button cancel = new Button(cancelLabel);
      cancel.setActionCommand("cancel");
      cancel.addActionListener(listener);
      buttonbox.add(cancel);
    }
    // Finally, set the dialog to its preferred size and display it.
    frame.pack();
    frame.show();
  }
  /**
   * A main method that demonstrates how to use this class, and allows testing.
   */
  public static void main(String[] args) {
    // Create an instance of InfoDialog, with title and message specified:
    YesNoDialog d =
      new YesNoDialog("YesNoDialog Test",
                      "There are unsaved files.\n" +
                      "Do you want to save them before quitting?",
                      "Yes, save and quit",
                      "No, quit without saving",
                      "Cancel; don't quit",
                      YesNoDialog.CENTER);
    // Register an action listener for the dialog.  This one just prints
    // the results out to the console.
    d.addAnswerListener(new AnswerListener() {
      public void yes(AnswerEvent e) { System.out.println("Yes"); }
      public void no(AnswerEvent e) { System.out.println("No"); }
      public void cancel(AnswerEvent e) { System.out.println("Cancel"); }
    });
    // Now pop the dialog up.  It will pop itself down automatically.
    d.display();
  }
}
</PRE>
</DIV>

</DIV>

</DIV>


<DIV CLASS=htmlnav>

<P>
<HR align=left width=515>
<table width=515 border=0 cellpadding=0 cellspacing=0>
<tr>
<td width=172 align=left valign=top><A HREF="ch10_02.htm"><IMG SRC="gifs/txtpreva.gif" ALT="Previous" border=0></A></td>
<td width=171 align=center valign=top><a href="index.htm"><img src='gifs/txthome.gif' border=0 alt='Home'></a></td>
<td width=172 align=right valign=top><A HREF="ch10_04.htm"><IMG SRC="gifs/txtnexta.gif" ALT="Next" border=0></A></td>
</tr>
<tr>
<td width=172 align=left valign=top>A Simple Bean</td>
<td width=171 align=center valign=top><a href="index/idx_0.htm"><img src='gifs/index.gif' alt='Book Index' border=0></a></td>
<td width=172 align=right valign=top>Custom Events</td>
</tr>
</table>
<hr align=left width=515>

<IMG SRC="gifs/smnavbar.gif" USEMAP="#map" BORDER=0> 
<MAP NAME="map"> 
<AREA SHAPE=RECT COORDS="0,0,108,15" HREF="../javanut/index.htm"
alt="Java in a Nutshell"> 
<AREA SHAPE=RECT COORDS="109,0,200,15" HREF="../langref/index.htm" 
alt="Java Language Reference"> 
<AREA SHAPE=RECT COORDS="203,0,290,15" HREF="../awt/index.htm" 
alt="Java AWT"> 
<AREA SHAPE=RECT COORDS="291,0,419,15" HREF="../fclass/index.htm" 
alt="Java Fundamental Classes"> 
<AREA SHAPE=RECT COORDS="421,0,514,15" HREF="../exp/index.htm" 
alt="Exploring Java"> 
</MAP>
</DIV>

</BODY>
</HTML>
